#include <scdl/parser/Symbol.hpp>

#include <cstdlib>
#include <cstring>
#include <iostream>

using std::cout;
using namespace scdl;

Identifier::Identifier()
        : category(CATEGORY_ASSUMPTION), def(0), binder(0)
{
}

Identifier::~Identifier()
{
        if (def)
                def->unref();
        if (binder)
                delete[] binder;
}

SymbolCategory Identifier::getCategory()
{
        return category;
}

void Identifier::prettyPrint(bool verbose)
{
        cout << name;
        if (verbose && type) {
                cout << " : ";
                type->prettyPrint();
        }
        if (verbose)
                switch(category) {
                case CATEGORY_DEFINITION:
                        if (def) {
                                cout << " := ";
                                def->prettyPrint();
                        }
                        break;
                case CATEGORY_INTERFACE:
                        if (binder)
                                cout << " := " << binder;
                        if (def)
                                def->prettyPrint();
                        else
                                cout << "{}";
                        break;
                case CATEGORY_INDUCTIVE_CTOR:
                        cout << " (" << indCtorValue << ")";
                        break;
                }
}

void Identifier::setDef(Symbol *sym)
{
        if (def)
                def->unref();

        def = sym;
        sym->ref();

        category = CATEGORY_DEFINITION;
}

Symbol *Identifier::getDef()
{
        if (category != CATEGORY_DEFINITION)
                return 0;
        return def;
}

void Identifier::setBinder(const char *binder)
{
        if (this->binder)
                delete[] this->binder;

        int len = strlen(binder);
        char *buf = new char[len + 1];
        memcpy(buf, binder, len + 1);
        this->binder = buf;

        category = CATEGORY_INTERFACE;
}

void Identifier::setRecord(Record *record)
{
        def = record;
        category = CATEGORY_INTERFACE;
}

const char *Identifier::getBinder()
{
        if (category != CATEGORY_INTERFACE)
                return 0;
        return binder;
}

Record *Identifier::getRecord()
{
        if (category != CATEGORY_INTERFACE)
                return 0;
        return static_cast<Record *>(def);
}

void Identifier::setInductiveCtorValue(int v)
{
        indCtorValue = v;
        category = CATEGORY_INDUCTIVE_CTOR;
}

int Identifier::getInductiveCtorValue()
{
        if (category != CATEGORY_INDUCTIVE_CTOR)
                return 0;
        return indCtorValue;
}
